package com.newmuis.open.codeeval.moderate;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Comparator;
import java.util.PriorityQueue;

/**
 * CodeEval.com > Moderate Challenges > Longest Lines
 * 
 * Description:
 * 
 * Write a program to read a multiple line text file and write the 'N' longest lines to stdout.
 * Where the file to be read is specified on the command line.
 * 
 * Input sample:
 * 
 * Your program should read an input file (the first argument to your program). The first line
 * contains the value of the number 'N' followed by multiple lines. You may assume that the input
 * file is formatted correctly and the number on the first line i.e. 'N' is a valid positive
 * integer.e.g.
 * 
 * 2
 * Hello World
 * 
 * CodeEval
 * Quick Fox
 * A
 * San Francisco
 * 
 * Output sample:
 * 
 * The 'N' longest lines, newline delimited. Do NOT print out empty lines. Ignore all empty lines in
 * the input. Ensure that there are no trailing empty spaces on each line you print. Also ensure
 * that the lines are printed out in decreasing order of length i.e. the output should be sorted
 * based on their length e.g.
 * 
 * San Francisco
 * Hello World
 * 
 * @author Jonathan Newmuis (jon@newmuis.com)
 * @category moderate
 * 
 */
public class longestlines {
	/**
	 * @param args should contain only one CLI argument: the path to an input file which specifies
	 *            the input in the defined format.
	 * @throws IOException if there is a problem reading the given input file.
	 */
	public static void main(final String[] args) throws IOException {
		// Verify input argument length.
		if (args.length < 1) {
			throw new RuntimeException("Must specify input file path.");
		} else if (args.length > 1) {
			throw new RuntimeException("Illegal input arguments specified.");
		}

		// Read file from specified path.
		final BufferedReader reader = new BufferedReader(new FileReader(new File(args[0])));

		String line;
		int n;

		try {
			n = Integer.parseInt(reader.readLine());
		} catch (final NumberFormatException e) {
			throw new RuntimeException("Input file specified non-numeric limit argument.");
		}

		// Order elements by line length.
		final PriorityQueue<String> priorityQueue = new PriorityQueue<String>(n,
		        new LineLengthComparator());
		while ((line = reader.readLine()) != null) {
			priorityQueue.add(line);
		}

		// Get longest n elements.
		for (int i = 0; i < n; i++) {
			final String element = priorityQueue.poll();

			if (element == null) {
				break;
			}

			System.out.println(element);
		}
	}

	/**
	 * Compares {@link String} objects by their length.
	 */
	private static class LineLengthComparator implements Comparator<String> {
		@Override
		public int compare(final String a, final String b) {
			if (a.length() < b.length()) {
				return 1;
			} else {
				return -1;
			}
		}
	}
}
